From 454a736db481ae4527360d5630ca9cd4148567c9 Mon Sep 17 00:00:00 2001 From: "ach61@labyrinth.cl.cam.ac.uk" Date: Thu, 6 Mar 2003 15:52:22 +0000 Subject: [PATCH] bitkeeper revision 1.108 (3e676eb6Jy0anfrUlVCNnVZnDDSlQg) virtual block device support --- .rootkeys | 4 +- xen/drivers/block/xen_block.c | 100 ++- xen/drivers/block/xen_segment.c | 132 +++- xen/include/hypervisor-ifs/block.h | 6 +- xen/include/hypervisor-ifs/xeno-major.h | 37 ++ xen/include/xeno/major.h | 3 + xen/include/xeno/segment.h | 12 +- .../arch/xeno/drivers/block/Makefile | 2 +- .../arch/xeno/drivers/block/xl_block.c | 152 +++-- .../arch/xeno/drivers/block/xl_block_test.c | 3 +- .../arch/xeno/drivers/block/xl_segment.c | 586 +++++++++++------- .../arch/xeno/drivers/block/xl_segment_proc.c | 280 +++++++++ .../drivers/block/ll_rw_blk.c | 1 + .../include/linux/blk.h | 7 + .../include/linux/major.h | 3 +- xenolinux-2.4.21-pre4-sparse/init/do_mounts.c | 4 + 16 files changed, 1050 insertions(+), 282 deletions(-) create mode 100644 xen/include/hypervisor-ifs/xeno-major.h create mode 100644 xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_segment_proc.c diff --git a/.rootkeys b/.rootkeys index 211a86c6d7..d4cb1b1353 100644 --- a/.rootkeys +++ b/.rootkeys @@ -382,6 +382,7 @@ 3ddb79c2YTaZwOqWin9-QNgHge5RVw xen/include/hypervisor-ifs/block.h 3ddb79c25UE59iu4JJcbRalx95mvcg xen/include/hypervisor-ifs/hypervisor-if.h 3ddb79c2oRPrzClk3zbTkRHlpumzKA xen/include/hypervisor-ifs/network.h +3e676eb5yHx7feWgYoqlwD2Z9WsY1w xen/include/hypervisor-ifs/xeno-major.h 3ddb79c4qbCoOFHrv9sCGshbWzBVlQ xen/include/scsi/scsi.h 3ddb79c4R4iVwqIIeychVQYmIH4FUg xen/include/scsi/scsi_ioctl.h 3ddb79c4yw_mfd4Uikn3v_IOPRpa1Q xen/include/scsi/scsicam.h @@ -476,7 +477,8 @@ 3e5a4e65iHEuC5sjFhj42XALYbLVRw xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/Makefile 3e5a4e65pP5spJErBW69pJxSSdK9RA xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_block.c 3e5a4e65GtI9JZRAjuRdXaxt_4ohyQ xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_block_test.c -3e5d129aDldt6geU2-2SzBae34sQzg xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_segment.c +3e676eb5RXnHzSHgA1BvM0B1aIm4qg xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_segment.c +3e5d129aDldt6geU2-2SzBae34sQzg xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_segment_proc.c 3e5a4e65G3e2s0ghPMgiJ-gBTUJ0uQ xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/console/Makefile 3e5a4e651TH-SXHoufurnWjgl5bfOA xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/console/console.c 3e5a4e656nfFISThfbyXQOA6HN6YHw xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/dom0/Makefile diff --git a/xen/drivers/block/xen_block.c b/xen/drivers/block/xen_block.c index 8e1ff1188b..0e6a82ccc3 100644 --- a/xen/drivers/block/xen_block.c +++ b/xen/drivers/block/xen_block.c @@ -41,7 +41,8 @@ static atomic_t nr_pending; static void io_schedule(unsigned long unused); static int do_block_io_op_domain(struct task_struct *p, int max_to_do); static void dispatch_rw_block_io(struct task_struct *p, int index); -static void dispatch_probe_block_io(struct task_struct *p, int index); +static void dispatch_probe_blk(struct task_struct *p, int index); +static void dispatch_probe_seg(struct task_struct *p, int index); static void dispatch_debug_block_io(struct task_struct *p, int index); static void dispatch_create_segment(struct task_struct *p, int index); static void dispatch_delete_segment(struct task_struct *p, int index); @@ -202,8 +203,12 @@ static int do_block_io_op_domain(struct task_struct* p, int max_to_do) dispatch_rw_block_io(p, i); break; - case XEN_BLOCK_PROBE: - dispatch_probe_block_io(p, i); + case XEN_BLOCK_PROBE_BLK: + dispatch_probe_blk(p, i); + break; + + case XEN_BLOCK_PROBE_SEG: + dispatch_probe_seg(p, i); break; case XEN_BLOCK_DEBUG: @@ -248,6 +253,7 @@ static void dispatch_create_segment(struct task_struct *p, int index) xvd = phys_to_virt((unsigned long)blk_ring->ring[index].req.buffer); result = xen_segment_create(xvd); + make_response(p, blk_ring->ring[index].req.id, XEN_BLOCK_SEG_CREATE, result); return; @@ -258,7 +264,7 @@ static void dispatch_delete_segment(struct task_struct *p, int index) DPRINTK("dispatch_delete_segment: unimplemented\n"); } -static void dispatch_probe_block_io(struct task_struct *p, int index) +static void dispatch_probe_blk(struct task_struct *p, int index) { extern void ide_probe_devices(xen_disk_info_t *xdi, int *count, drive_t xdrives[]); @@ -269,7 +275,19 @@ static void dispatch_probe_block_io(struct task_struct *p, int index) ide_probe_devices(xdi, &num_xdrives, xdrives); /* scsi_probe_devices(xdi, &num_xdrives, xdrives); */ /* future */ - make_response(p, blk_ring->ring[index].req.id, XEN_BLOCK_PROBE, 0); + make_response(p, blk_ring->ring[index].req.id, XEN_BLOCK_PROBE_BLK, 0); +} + +static void dispatch_probe_seg(struct task_struct *p, int index) +{ + extern void xen_segment_probe(xen_disk_info_t *xdi, int *count); + blk_ring_t *blk_ring = p->blk_ring_base; + xen_disk_info_t *xdi; + + xdi = phys_to_virt((unsigned long)blk_ring->ring[index].req.buffer); + xen_segment_probe(xdi, &num_xdrives); + + make_response(p, blk_ring->ring[index].req.id, XEN_BLOCK_PROBE_SEG, 0); } static void dispatch_rw_block_io(struct task_struct *p, int index) @@ -279,8 +297,11 @@ static void dispatch_rw_block_io(struct task_struct *p, int index) struct buffer_head *bh; int operation; unsigned short size; + unsigned long block_number = 0L; + unsigned long sector_number = 0L; unsigned long buffer, pfn; struct pfn_info *page; + int xen_device, phys_device = 0; operation = (blk_ring->ring[index].req.operation == XEN_BLOCK_WRITE) ? WRITE : READ; @@ -345,11 +366,50 @@ static void dispatch_rw_block_io(struct task_struct *p, int index) /* set just the important bits of the buffer header */ memset (bh, 0, sizeof (struct buffer_head)); + + /* map from virtual xeno devices to physical ide & scsi devices */ + xen_device = blk_ring->ring[index].req.device; + if (IS_XHD_MAJOR(xen_device)) + { + if (xen_device == XHDA_MAJOR) phys_device = MKDEV(IDE0_MAJOR, 0); + else if (xen_device == XHDB_MAJOR) phys_device = MKDEV(IDE1_MAJOR, 0); + else if (xen_device == XHDC_MAJOR) phys_device = MKDEV(IDE2_MAJOR, 0); + else if (xen_device == XHDD_MAJOR) phys_device = MKDEV(IDE3_MAJOR, 0); + else + { + printk (KERN_ALERT "dispatch_rw_block_io: unknown device %d\n", + xen_device); + BUG(); + } + + block_number = blk_ring->ring[index].req.block_number; + sector_number = blk_ring->ring[index].req.sector_number; + } + else if (IS_VHD_MAJOR(xen_device)) + { + int s; + if (s = xen_segment_map_request(&phys_device, &block_number, + §or_number, + p, operation, xen_device, + blk_ring->ring[index].req.block_number, + blk_ring->ring[index].req.sector_number)) + { + printk ("dispatch_rw_block_io: xen_segment_map_request status: %d\n", + s); + goto bad_descriptor; + } + } + else + { + printk (KERN_ALERT "dispatch_rw_block_io: unknown device %d\n", + xen_device); + BUG(); + } - bh->b_blocknr = blk_ring->ring[index].req.block_number; + bh->b_blocknr = block_number; bh->b_size = size; - bh->b_dev = blk_ring->ring[index].req.device; - bh->b_rsector = blk_ring->ring[index].req.sector_number; + bh->b_dev = phys_device; + bh->b_rsector = sector_number; bh->b_data = phys_to_virt(buffer); bh->b_count.counter = 1; bh->b_end_io = end_block_io_op; @@ -373,6 +433,7 @@ static void dispatch_rw_block_io(struct task_struct *p, int index) return; bad_descriptor: + printk (KERN_ALERT "dispatch rw blockio bad descriptor\n"); make_response(p, blk_ring->ring[index].req.id, XEN_BLOCK_READ, 1); return; } @@ -407,8 +468,23 @@ static void make_response(struct task_struct *p, void *id, static void dump_blockq(u_char key, void *dev_id, struct pt_regs *regs) { - printk("Dumping block queue stats: nr_pending = %d\n", - atomic_read(&nr_pending)); + struct task_struct *p; + blk_ring_t *blk_ring ; + + printk("Dumping block queue stats: nr_pending = %d\n", + atomic_read(&nr_pending)); + + p = current->next_task; + do + { + printk (KERN_ALERT "Domain: %d\n", p->domain); + blk_ring = p->blk_ring_base; + + printk(" req_prod:%d, resp_prod:%d, req_cons:%d\n", + blk_ring->req_prod, blk_ring->resp_prod, p->blk_req_cons); + + p = p->next_task; + } while (p != current); } /* Start-of-day initialisation for a new domain. */ @@ -419,7 +495,11 @@ void init_blkdev_info(struct task_struct *p) clear_page(p->blk_ring_base); SHARE_PFN_WITH_DOMAIN(virt_to_page(p->blk_ring_base), p->domain); p->blkdev_list.next = NULL; + + memset(p->segment_list, 0, sizeof(p->segment_list)); p->segment_count = 0; + + xen_refresh_segment_list(p); /* get any previously created segments */ } /* End-of-day teardown for a domain. XXX Outstanding requests? */ diff --git a/xen/drivers/block/xen_segment.c b/xen/drivers/block/xen_segment.c index 1105afe1c7..c326138c30 100644 --- a/xen/drivers/block/xen_segment.c +++ b/xen/drivers/block/xen_segment.c @@ -9,14 +9,116 @@ #include #include #include +#include #include +#include +#include #include +#include int num_xdrives; drive_t xdrives[XEN_MAX_DISK_COUNT]; segment_t xsegments[XEN_MAX_SEGMENTS]; +/* + * xen_segment_map_request + * + * xen_device must be a valid device. + */ + +int xen_segment_map_request(int *phys_device, /* out */ + unsigned long *block_number, /* out */ + unsigned long *sector_number, /* out */ + struct task_struct *domain, + int operation, + int xen_device, + int xen_block_number, + int xen_sector_number) +{ + segment_t *seg; + int segment_number; /* segment number within this domain */ + int sum; + int loop; + + segment_number = xen_device - XLSEG_MAJOR; + seg = domain->segment_list[segment_number]; + + if (seg == NULL) + { + return 1; /* oops. no vhd exists! */ + } + + /* check domain permissions */ + if (seg->domain != domain->domain) + { + return 2; /* domain doesn't own segment */ + } + + /* check rw access */ + if ((operation == WRITE && seg->mode != XEN_SEGMENT_RW) || + (operation == READ && seg->mode == XEN_SEGMENT_UNUSED)) + { + return 3; /* access violation */ + } + + /* find extent, check size */ + sum = 0; + loop = 0; + while (loop < seg->num_extents && sum <= xen_block_number) + { + sum += seg->extents[loop++].size; + } + sum -= seg->extents[--loop].size; /* rewind */ + + if (sum + seg->extents[loop].size <= xen_block_number) + { + return 4; /* tried to read past the end of the segment */ + } + *block_number = xen_block_number - sum + seg->extents[loop].offset; + *sector_number = xen_sector_number - sum + seg->extents[loop].offset;; + + /* get physical device from xdrives */ + *phys_device = MKDEV(xdrives[seg->extents[loop].disk].major, 0); + + /* + printk ("%d %lx %lx %lx %lx : %lx %lx %lx %lx\n", + operation, + *block_number, xen_block_number, sum, seg->extents[loop].offset, + *sector_number, xen_sector_number, sum, seg->extents[loop].offset + ); + */ + + return 0; +} + +/* + * xen_segment_probe + * + * return a list of segments to the guestos + */ +void xen_segment_probe (xen_disk_info_t *raw_xdi, int *count) +{ + int loop, i; + xen_disk_info_t *xdi = map_domain_mem(virt_to_phys(raw_xdi)); + + for (loop = 0; loop < XEN_MAX_SEGMENTS; loop++ ) + { + if (xsegments[loop].mode != XEN_SEGMENT_UNUSED) + { + xdi->disks[xdi->count].type = XEN_DISK_VIRTUAL; + for (i = 0; i < xsegments[loop].num_extents; i++) + { + xdi->disks[xdi->count].capacity += xsegments[loop].extents[i].size; + } + xdi->count++; + } + } + + unmap_domain_mem(xdi); + return; +} + /* * xen_refresh_segment_list * @@ -59,7 +161,8 @@ int xen_segment_create(xv_disk_t *xvd_in) } if (idx == XEN_MAX_SEGMENTS) { - printk (KERN_ALERT "error: xen_segment_create unable to find free slot\n"); + printk (KERN_ALERT "xen_segment_create: unable to find free slot\n"); + unmap_domain_mem(xvd); return 1; } @@ -76,8 +179,16 @@ int xen_segment_create(xv_disk_t *xvd_in) xsegments[idx].extents[loop].disk = xvd->extents[loop].disk; xsegments[idx].extents[loop].offset = xvd->extents[loop].offset; xsegments[idx].extents[loop].size = xvd->extents[loop].size; + if (xsegments[idx].extents[loop].size == 0) + { + printk (KERN_ALERT "xen_segment_create: extent %d is zero length\n", + loop); + unmap_domain_mem(xvd); + return 1; + } } + unmap_domain_mem(xvd); return 0; } @@ -96,6 +207,7 @@ int xen_segment_delete(struct task_struct *p, xv_disk_t *xvd) static void dump_segments(u_char key, void *dev_id, struct pt_regs *regs) { int loop, i; + struct task_struct *p; printk (KERN_ALERT "xdrives\n"); for (loop = 0; loop < num_xdrives; loop++) @@ -103,7 +215,7 @@ static void dump_segments(u_char key, void *dev_id, struct pt_regs *regs) printk (KERN_ALERT " %2d: major: 0x%d\n", loop, xdrives[loop].major); } - printk (KERN_ALERT "segments\n"); + printk (KERN_ALERT "segment list\n"); for (loop = 0; loop < XEN_MAX_SEGMENTS; loop++) { if (xsegments[loop].mode != XEN_SEGMENT_UNUSED) @@ -122,6 +234,22 @@ static void dump_segments(u_char key, void *dev_id, struct pt_regs *regs) } } } + + printk (KERN_ALERT "segments by domain\n"); + p = current->next_task; + do + { + printk (KERN_ALERT " domain: %d\n", p->domain); + for (loop = 0; loop < p->segment_count; loop++) + { + printk (KERN_ALERT " mode:%d domain:%d seg:%d exts:%d\n", + p->segment_list[loop]->mode, + p->segment_list[loop]->domain, + p->segment_list[loop]->segment_number, + p->segment_list[loop]->num_extents); + } + p = p->next_task; + } while (p != current); } /* diff --git a/xen/include/hypervisor-ifs/block.h b/xen/include/hypervisor-ifs/block.h index 908f8382cc..9459cdc17e 100644 --- a/xen/include/hypervisor-ifs/block.h +++ b/xen/include/hypervisor-ifs/block.h @@ -22,10 +22,11 @@ #define XEN_BLOCK_WRITE 1 #define XEN_BLOCK_READA 2 /* currently unused */ #define XEN_BLOCK_SPECIAL 4 /* currently unused */ -#define XEN_BLOCK_PROBE 8 /* determine io configuration from hypervisor */ -#define XEN_BLOCK_DEBUG 16 /* debug */ +#define XEN_BLOCK_PROBE_BLK 8 /* get xhd config from hypervisor */ +#define XEN_BLOCK_DEBUG 16 /* debug */ #define XEN_BLOCK_SEG_CREATE 32 /* create segment (vhd) */ #define XEN_BLOCK_SEG_DELETE 64 /* delete segment (vhd) */ +#define XEN_BLOCK_PROBE_SEG 128 /* get vhd config from hypervisor */ #define BLK_RING_SIZE 128 #define BLK_RING_MAX_ENTRIES (BLK_RING_SIZE - 2) @@ -70,6 +71,7 @@ typedef struct blk_ring_st #define XEN_DISK_IDE 1 #define XEN_DISK_SCSI 2 +#define XEN_DISK_VIRTUAL 3 /* vhd */ typedef struct xen_disk /* physical disk */ { diff --git a/xen/include/hypervisor-ifs/xeno-major.h b/xen/include/hypervisor-ifs/xeno-major.h new file mode 100644 index 0000000000..099fe270c9 --- /dev/null +++ b/xen/include/hypervisor-ifs/xeno-major.h @@ -0,0 +1,37 @@ +/* + * xeno_major.h + * + * shared definitions for block IO. + */ + +/* + * this belongs in xenolinux/include/linux/major.h except that + * xen also needs access... + */ + + +#ifndef __XENO_MAJOR_H__ +#define __XENO_MAJOR_H__ + + +#define XLBLK_MAJOR 123 /* XenoLinux Block Device: xhd */ +#define XHDA_MAJOR 123 +#define XHDB_MAJOR 124 +#define XHDC_MAJOR 125 +#define XHDD_MAJOR 126 +#define XLSEG_MAJOR 234 /* XenoLinux Segment Device: vhd */ +#define VHDA_MAJOR 234 +#define VHDB_MAJOR 235 +#define VHDC_MAJOR 236 +#define VHDD_MAJOR 237 + + +/* + * XenoLinux Block Device Tests + */ +#define IS_XHD_MAJOR(M) ( (M) == XHDA_MAJOR || (M) == XHDB_MAJOR || \ + (M) == XHDC_MAJOR || (M) == XHDD_MAJOR ? 1 : 0) +#define IS_VHD_MAJOR(M) ( (M) == VHDA_MAJOR || (M) == VHDB_MAJOR || \ + (M) == VHDC_MAJOR || (M) == VHDD_MAJOR ? 1 : 0) + +#endif diff --git a/xen/include/xeno/major.h b/xen/include/xeno/major.h index b30f88baf8..f3a44119fc 100644 --- a/xen/include/xeno/major.h +++ b/xen/include/xeno/major.h @@ -144,6 +144,9 @@ #define UMEM_MAJOR 116 /* http://www.umem.com/ Battery Backed RAM */ +/* note: 123, 124, 125, 126 and 234, 235, 236, 237 are defined in xeno_major */ +#include + #define RTF_MAJOR 150 #define RAW_MAJOR 162 diff --git a/xen/include/xeno/segment.h b/xen/include/xeno/segment.h index f0bf08ffbd..4045da3849 100644 --- a/xen/include/xeno/segment.h +++ b/xen/include/xeno/segment.h @@ -6,6 +6,14 @@ void xen_segment_initialize(void); void xen_refresh_segment_list (struct task_struct *p); int xen_segment_create(xv_disk_t *xvd); +int xen_segment_map_request(int *phys_device, /* out */ + unsigned long *block_number, /* out */ + unsigned long *sector_number, /* out */ + struct task_struct *domain, + int operation, + int xen_device, + int xen_block_number, + int xen_sector_number); #define XEN_MAX_SEGMENTS 100 /* total number of segments across all doms */ @@ -37,8 +45,8 @@ typedef struct extent } extent_t; #define XEN_SEGMENT_UNUSED 0 /* bzero default */ -#define XEN_SEGMENT_RO XEN_DISK_READ_WRITE -#define XEN_SEGMENT_RW XEN_DISK_READ_ONLY +#define XEN_SEGMENT_RO XEN_DISK_READ_ONLY +#define XEN_SEGMENT_RW XEN_DISK_READ_WRITE typedef struct segment { diff --git a/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/Makefile b/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/Makefile index c6d1c7dc63..594aab25b8 100644 --- a/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/Makefile +++ b/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/Makefile @@ -1,3 +1,3 @@ O_TARGET := blk.o -obj-y := xl_block.o xl_segment.o xl_block_test.o +obj-y := xl_block.o xl_segment.o xl_segment_proc.o xl_block_test.o include $(TOPDIR)/Rules.make diff --git a/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_block.c b/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_block.c index 6e7e713c86..bc87e7eb7b 100644 --- a/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_block.c +++ b/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_block.c @@ -1,7 +1,7 @@ /****************************************************************************** * xl_block.c * - * Xenolinux virtual block-device driver. + * Xenolinux virtual block-device driver (xhd). * */ @@ -32,8 +32,6 @@ static int xlblk_major = XLBLK_MAJOR; /* Copied from linux/ide.h */ typedef unsigned char byte; -void xlblk_ide_register_disk(int, unsigned long); - #define XLBLK_MAX 32 /* Maximum minor devices we support */ #define XLBLK_MAJOR_NAME "xhd" #define IDE_PARTN_BITS 6 /* from ide.h::PARTN_BITS */ @@ -58,15 +56,18 @@ static int xlblk_max_sectors[XLBLK_MAX]; static blk_ring_t *blk_ring; static unsigned int resp_cons; /* Response consumer for comms ring. */ -static xen_disk_info_t xen_disk_info; +static xen_disk_info_t xlblk_disk_info; atomic_t xlblk_control_count; -int hypervisor_request(void * id, - int operation, - char * buffer, - unsigned long block_number, - unsigned short block_size, - kdev_t device); +void xlblk_ide_register_disk(int, unsigned long); +void do_xlseg_requestX (request_queue_t *rq); +int hypervisor_request(void * id, + int operation, + char * buffer, + unsigned long block_number, + unsigned short block_size, + kdev_t device, + struct gendisk *gd); /* ------------------------------------------------------------------------ @@ -103,22 +104,39 @@ static int xenolinux_block_ioctl(struct inode *inode, struct file *filep, switch (command) { - case BLKGETSIZE: + case BLKGETSIZE: /* get size */ DPRINTK_IOCTL(" BLKGETSIZE: %x %lx\n", BLKGETSIZE, - (long) xen_disk_info.disks[0].capacity); - return put_user(xen_disk_info.disks[0].capacity, + (long) xlblk_disk_info.disks[0].capacity); + return put_user(xlblk_disk_info.disks[0].capacity, (unsigned long *) argument); - case BLKRRPART: + case BLKRRPART: /* re-read partition table */ DPRINTK_IOCTL(" BLKRRPART: %x\n", BLKRRPART); break; - case BLKSSZGET: + case BLKBSZGET: /* get block size */ + DPRINTK_IOCTL(" BLKBSZGET: %x\n", BLKBSZGET); + break; + + case BLKBSZSET: /* set block size */ + DPRINTK_IOCTL(" BLKBSZSET: %x\n", BLKBSZSET); + break; + + case BLKRASET: /* set read-ahead */ + DPRINTK_IOCTL(" BLKRASET: %x\n", BLKRASET); + break; + + case BLKRAGET: /* get read-ahead */ + DPRINTK_IOCTL(" BLKRAFET: %x\n", BLKRAGET); + break; + + case BLKSSZGET: /* get sector size */ DPRINTK_IOCTL(" BLKSSZGET: %x 0x%x\n", BLKSSZGET, xlblk_hardsect_size[minor_dev]); return xlblk_hardsect_size[minor_dev]; case HDIO_GETGEO: + /* note: these values are complete garbage */ DPRINTK_IOCTL(" HDIO_GETGEO: %x\n", HDIO_GETGEO); if (!argument) return -EINVAL; if (put_user(0x00, (unsigned long *) &geo->start)) return -EFAULT; @@ -128,13 +146,13 @@ static int xenolinux_block_ioctl(struct inode *inode, struct file *filep, return 0; case HDIO_GETGEO_BIG: + /* note: these values are complete garbage */ DPRINTK_IOCTL(" HDIO_GETGEO_BIG: %x\n", HDIO_GETGEO_BIG); if (!argument) return -EINVAL; if (put_user(0x00, (unsigned long *) &geo->start)) return -EFAULT; if (put_user(0xff, (byte *)&geo->heads)) return -EFAULT; if (put_user(0x3f, (byte *)&geo->sectors)) return -EFAULT; if (put_user(0x106, (unsigned int *) &geo->cylinders)) return -EFAULT; - return 0; default: @@ -163,26 +181,27 @@ static int xenolinux_block_revalidate(kdev_t dev) * request block io * * id: for guest use only. - * operation: XEN_BLOCK_READ, XEN_BLOCK_WRITE or XEN_BLOCK_PROBE + * operation: XEN_BLOCK_{READ,WRITE,PROBE*,SEG*} * buffer: buffer to read/write into. this should be a * virtual address in the guest os. * block_number: block to read * block_size: size of each block - * device: ide/hda is 768 or 0x300 should be disk#!!! + * device: xhd or vhd + * gd: partition information if XEN_BLOCK_{READ,WRITE} */ -int hypervisor_request(void * id, - int operation, - char * buffer, - unsigned long block_number, - unsigned short block_size, - kdev_t device) +int hypervisor_request(void * id, + int operation, + char * buffer, + unsigned long block_number, + unsigned short block_size, + kdev_t device, + struct gendisk *gd) { int position; void *buffer_ma; kdev_t phys_device = (kdev_t) 0; unsigned long sector_number = 0; - struct gendisk *gd; - + /* * Bail if there's no room in the request communication ring. This may be * because we have a whole bunch of outstanding responses to process. No @@ -197,21 +216,38 @@ int hypervisor_request(void * id, { case XEN_BLOCK_SEG_CREATE: case XEN_BLOCK_SEG_DELETE: - case XEN_BLOCK_PROBE: + case XEN_BLOCK_PROBE_BLK: + case XEN_BLOCK_PROBE_SEG: phys_device = (kdev_t) 0; sector_number = 0; break; case XEN_BLOCK_READ: case XEN_BLOCK_WRITE: - if ( MAJOR(device) != XLBLK_MAJOR ) + /* only accept requests for xhd and vhd devices */ + if (!IS_XHD_MAJOR(MAJOR(device)) && !IS_VHD_MAJOR(MAJOR(device))) panic("error: xl_block::hypervisor_request: " "unknown device [0x%x]\n", device); - phys_device = MKDEV(IDE0_MAJOR, 0); - /* Compute real buffer location on disk */ + phys_device = MAJOR(device); + + /* Compute real buffer location on disk. + * note: gd will be null when we read the partition table. + */ sector_number = block_number; - if ( (gd = (struct gendisk *)xen_disk_info.disks[0].gendisk) != NULL ) - sector_number += gd->part[MINOR(device)&IDE_PARTN_MASK].start_sect; + if ( gd != NULL ) + { + sector_number += gd->part[MINOR(device)&IDE_PARTN_MASK].start_sect; + } + + /* + if (IS_VHD_MAJOR(MAJOR(device))) + { + printk (KERN_ALERT "%lx + %lx = %lx (%x)\n", + block_number, + gd->part[MINOR(device)&IDE_PARTN_MASK].start_sect, + sector_number, device); + } + */ break; default: @@ -266,8 +302,9 @@ static void do_xlblk_request (request_queue_t *rq) { full = hypervisor_request( bh, (rw == READ) ? XEN_BLOCK_READ : XEN_BLOCK_WRITE, - bh->b_data, bh->b_rsector, bh->b_size, bh->b_dev); - + bh->b_data, bh->b_rsector, bh->b_size, bh->b_dev, + (struct gendisk *)xlblk_disk_info.disks[0].gendisk); + if ( full ) goto out; queued++; @@ -334,6 +371,7 @@ static void xlblk_response_int(int irq, void *dev_id, struct pt_regs *ptregs) case XEN_BLOCK_SEG_CREATE : case XEN_BLOCK_SEG_DELETE : + case XEN_BLOCK_PROBE_SEG : atomic_dec(&xlblk_control_count); break; @@ -345,7 +383,9 @@ static void xlblk_response_int(int irq, void *dev_id, struct pt_regs *ptregs) resp_cons = i; /* KAF: We can push work down at this point. We have the lock. */ - do_xlblk_request(BLK_DEFAULT_QUEUE(MAJOR_NR)); + /* aho: okay, so this is a bit of a hack. we'll kick every queue... */ + do_xlblk_request(BLK_DEFAULT_QUEUE(XLBLK_MAJOR)); + do_xlseg_requestX(BLK_DEFAULT_QUEUE(XLSEG_MAJOR)); spin_unlock_irqrestore(&io_request_lock, flags); } @@ -368,20 +408,23 @@ int __init xlblk_init(void) goto fail; } - memset (&xen_disk_info, 0, sizeof(xen_disk_info)); - xen_disk_info.count = 0; + /* probe for disk information */ + memset (&xlblk_disk_info, 0, sizeof(xlblk_disk_info)); + xlblk_disk_info.count = 0; - if ( hypervisor_request(NULL, XEN_BLOCK_PROBE, (char *) &xen_disk_info, - 0, 0, (kdev_t) 0) ) + if ( hypervisor_request(NULL, XEN_BLOCK_PROBE_BLK, + (char *) &xlblk_disk_info, + 0, 0, (kdev_t) 0, + (struct gendisk *) NULL)) BUG(); HYPERVISOR_block_io_op(); while ( blk_ring->resp_prod != 1 ) barrier(); - printk (KERN_ALERT "block device probe:\n"); - for ( i = 0; i < xen_disk_info.count; i++ ) + printk (KERN_ALERT "xhd block device probe:\n"); + for ( i = 0; i < xlblk_disk_info.count; i++ ) { printk (KERN_ALERT " %2d: type: %d, capacity: %ld\n", - i, xen_disk_info.disks[i].type, - xen_disk_info.disks[i].capacity); + i, xlblk_disk_info.disks[i].type, + xlblk_disk_info.disks[i].capacity); } SET_MODULE_OWNER(&xenolinux_block_fops); @@ -394,7 +437,7 @@ int __init xlblk_init(void) /* initialize global arrays in drivers/block/ll_rw_block.c */ for (i = 0; i < XLBLK_MAX; i++) { - xlblk_blk_size[i] = xen_disk_info.disks[0].capacity; + xlblk_blk_size[i] = xlblk_disk_info.disks[0].capacity; xlblk_blksize_size[i] = 512; xlblk_hardsect_size[i] = 512; xlblk_max_sectors[i] = 128; @@ -415,7 +458,7 @@ int __init xlblk_init(void) */ blk_queue_headactive(BLK_DEFAULT_QUEUE(xlblk_major), 0); - xlblk_ide_register_disk(0, xen_disk_info.disks[0].capacity); + xlblk_ide_register_disk(0, xlblk_disk_info.disks[0].capacity); printk(KERN_ALERT "XenoLinux Virtual Block Device Driver installed [device: %d]\n", @@ -461,13 +504,26 @@ void xlblk_ide_register_disk(int idx, unsigned long capacity) add_gendisk(gd); - xen_disk_info.disks[idx].gendisk = gd; + xlblk_disk_info.disks[idx].gendisk = gd; - /* default disk size is just a big number. in the future, we - need a message to probe the devices to determine the actual size */ register_disk(gd, MKDEV(xlblk_major, 0), 1<part[loop].start_sect && gd->part[loop].nr_sects) + { + printk (KERN_ALERT + " %2d: 0x%6lx %8ld 0x%6lx %7ld\n", loop, + gd->part[loop].start_sect, gd->part[loop].start_sect, + gd->part[loop].nr_sects, gd->part[loop].nr_sects); + } + } + } + return; } diff --git a/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_block_test.c b/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_block_test.c index 8d695689ba..b239655794 100644 --- a/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_block_test.c +++ b/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_block_test.c @@ -206,7 +206,8 @@ int proc_write_bdt(struct file *file, const char *buffer, /* submit request */ hypervisor_request(0, meta.operation, meta.buffer, meta.block_number, meta.block_size, - meta.device); + meta.device, + (struct gendisk *) NULL); HYPERVISOR_block_io_op(); mdelay(1000); /* should wait for a proper acknowledgement/response. */ diff --git a/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_segment.c b/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_segment.c index da14be14df..0754daa9a3 100644 --- a/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_segment.c +++ b/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_segment.c @@ -1,274 +1,432 @@ -/* +/****************************************************************************** * xl_segment.c * - * XenoLinux virtual disk driver. + * Xenolinux virtual block-device driver (vhd). + * */ - #include #include -#include -#include -#include -#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include #include #include +#include +#include +#include + +#define MAJOR_NR XLSEG_MAJOR /* force defns in blk.h, must precede include */ +static int xlseg_major = XLSEG_MAJOR; +#include + +/* Copied from linux/ide.h */ +typedef unsigned char byte; -static struct proc_dir_entry *vhd; -xv_disk_t xvd; +#define XLSEG_MAX 32 /* Maximum minor devices we support */ +#define XLSEG_MAJOR_NAME "xhd" + +static int xlseg_blk_size[XLSEG_MAX]; +static int xlseg_blksize_size[XLSEG_MAX]; +static int xlseg_read_ahead; +static int xlseg_hardsect_size[XLSEG_MAX]; +static int xlseg_max_sectors[XLSEG_MAX]; extern atomic_t xlblk_control_count; /* xl_block.c */ -/******************************************************************/ +int hypervisor_request(void * id, + int operation, + char * buffer, + unsigned long block_number, + unsigned short block_size, + kdev_t device, + struct gendisk *gd); +void xlseg_register_disk(int idx, unsigned long capacity); + +#if 0 +#define DPRINTK(_f, _a...) printk ( KERN_ALERT _f , ## _a ) +#define DPRINTK_IOCTL(_f, _a...) printk ( KERN_ALERT _f , ## _a ) +#else +#define DPRINTK(_f, _a...) ((void)0) +#define DPRINTK_IOCTL(_f, _a...) ((void)0) +#endif + +static xen_disk_info_t xlseg_disk_info; -static int proc_read_vhd(char *page, char **start, off_t off, - int count, int *eof, void *data) +/* ------------------------------------------------------------------------ + */ + +static int xenolinux_segment_open(struct inode *inode, struct file *filep) { - return 0; + DPRINTK("xenolinux_segment_release\n"); + return 0; } -#define isdelim(c) \ - (c==' '||c==','||c=='\n'||c=='\r'||c=='\t'||c==':'||c=='('||c==')' ? 1 : 0) +static int xenolinux_segment_release(struct inode *inode, struct file *filep) +{ + DPRINTK("xenolinux_segment_release\n"); + return 0; +} -char *get_string(char *string) /* a bit like strtok */ +static int xenolinux_segment_ioctl(struct inode *inode, struct file *filep, + unsigned command, unsigned long argument) { - static char *temp; - int loop = 0; + int minor_dev; + struct hd_geometry *geo = (struct hd_geometry *)argument; + struct gendisk *gd = (struct gendisk *)xlseg_disk_info.disks[0].gendisk; + + DPRINTK("xenolinux_segment_ioctl\n"); + + /* check permissions */ + if (!capable(CAP_SYS_ADMIN)) return -EPERM; + if (!inode) return -EINVAL; + minor_dev = MINOR(inode->i_rdev); + if (minor_dev >= XLSEG_MAX) return -ENODEV; + + DPRINTK_IOCTL("command: 0x%x, argument: 0x%lx, minor: 0x%x\n", + command, (long) argument, minor_dev); + + switch (command) + { + case BLKGETSIZE: + if (gd != NULL) + { + printk(KERN_ALERT "minordev: %d\n", minor_dev); + printk(KERN_ALERT "[0] start: %lx\n", gd->part[0].start_sect); + printk(KERN_ALERT "[0] count: %lx\n", gd->part[0].nr_sects); + printk(KERN_ALERT "[1] start: %lx\n", gd->part[1].start_sect); + printk(KERN_ALERT "[1] count: %lx\n", gd->part[1].nr_sects); + printk(KERN_ALERT "[2] start: %lx\n", gd->part[2].start_sect); + printk(KERN_ALERT "[2] count: %lx\n", gd->part[2].nr_sects); + + DPRINTK_IOCTL(" BLKGETSIZE gd: %x %lx\n", BLKGETSIZE, + gd->part[minor_dev].nr_sects); + return put_user(gd->part[minor_dev].nr_sects, + (unsigned long *)argument); + } + else + { + DPRINTK_IOCTL(" BLKGETSIZE disk: %x %lx\n", BLKGETSIZE, + xlseg_disk_info.disks[0].capacity); + return put_user(xlseg_disk_info.disks[0].capacity, + (unsigned long *) argument); + } + + case BLKRRPART: + DPRINTK_IOCTL(" BLKRRPART: \n"); + /* we don't have re-validate drive yet... so you need to reboot! */ + break; + + case BLKSSZGET: + DPRINTK_IOCTL(" BLKSSZGET: %d\n", + xlseg_hardsect_size[minor_dev]); + return xlseg_hardsect_size[minor_dev]; + + case HDIO_GETGEO: + /* note: these values are complete garbage */ + DPRINTK_IOCTL(" HDIO_GETGEO: \n"); + if (!argument) return -EINVAL; + if (put_user(0x00, (unsigned long *) &geo->start)) return -EFAULT; + if (put_user(0xff, (byte *)&geo->heads)) return -EFAULT; + if (put_user(0x3f, (byte *)&geo->sectors)) return -EFAULT; + if (put_user(0x106, (unsigned short *)&geo->cylinders)) return -EFAULT; + return 0; + + case HDIO_GETGEO_BIG: + /* note: these values are complete garbage */ + DPRINTK_IOCTL(" HDIO_GETGEO_BIG\n"); + if (!argument) return -EINVAL; + if (put_user(0x00, (unsigned long *) &geo->start)) return -EFAULT; + if (put_user(0xff, (byte *)&geo->heads)) return -EFAULT; + if (put_user(0x3f, (byte *)&geo->sectors)) return -EFAULT; + if (put_user(0x106, (unsigned int *) &geo->cylinders)) return -EFAULT; + return 0; + + default: + DPRINTK_IOCTL(" eh? unknown ioctl\n"); + break; + } + + return 0; +} - if (string != NULL) - temp = string; - else - string = temp; +static int xenolinux_segment_check(kdev_t dev) +{ + DPRINTK("xenolinux_segment_check\n"); + return 0; +} - try_again: +static int xenolinux_segment_revalidate(kdev_t dev) +{ + DPRINTK("xenolinux_segment_revalidate\n"); + return 0; +} - while (!isdelim(string[loop])) - { - if (string[loop] == '\0') - return NULL; - loop++; - } +void do_xlseg_requestX (request_queue_t *rq) +{ + /* this is a bit dumb. do_xlseg_request is defined in blk.h + and this is thus static. but we have cooperative + device drivers... */ + do_xlseg_request(rq); +} - string[loop] = '\0'; - temp = (string + loop + 1); +/* + * do_xlseg_request + * read a block; request is in a request queue + */ +static void do_xlseg_request (request_queue_t *rq) +{ + struct request *req; + struct buffer_head *bh; + int rw, nsect, full, queued = 0; + + /* DPRINTK("do_xlseg_request for '%s'\n", DEVICE_NAME); */ - if (loop == 0) - { - string = temp; - goto try_again; - } + while ( !rq->plugged && !QUEUE_EMPTY ) + { + if ( (req = CURRENT) == NULL ) goto out; + + DPRINTK("do_xlseg_request %p: cmd %i, sec %lx, (%li/%li) bh:%p\n", + req, req->cmd, req->sector, + req->current_nr_sectors, req->nr_sectors, req->bh); + + rw = req->cmd; + if ( rw == READA ) rw = READ; + if ((rw != READ) && (rw != WRITE)) + panic("XenoLinux Virtual Segment Device: bad cmd: %d\n", rw); + + req->errors = 0; + + bh = req->bh; + while ( bh != NULL ) + { + full = hypervisor_request( + bh, (rw == READ) ? XEN_BLOCK_READ : XEN_BLOCK_WRITE, + bh->b_data, bh->b_rsector, bh->b_size, bh->b_dev, + (struct gendisk *)xlseg_disk_info.disks[0].gendisk); + + if ( full ) + { + goto out; + } + + queued++; + + /* Dequeue the buffer head from the request. */ + nsect = bh->b_size >> 9; + req->bh = bh->b_reqnext; + bh->b_reqnext = NULL; + bh = req->bh; + + if ( bh != NULL ) + { + /* There's another buffer head to do. Update the request. */ + req->hard_sector += nsect; + req->hard_nr_sectors -= nsect; + req->sector = req->hard_sector; + req->nr_sectors = req->hard_nr_sectors; + req->current_nr_sectors = bh->b_size >> 9; + req->buffer = bh->b_data; + } + else + { + /* That was the last buffer head. Finalise the request. */ + if ( end_that_request_first(req, 1, "XenSeg") ) BUG(); + blkdev_dequeue_request(req); + end_that_request_last(req); + } + } + } - return string; + out: + if ( queued != 0 ) HYPERVISOR_block_io_op(); } -#define isdigit(c) (c >= '0' && c <= '9' ? 1 : 0) -unsigned long to_number(char *string) /* atoi */ +static struct block_device_operations xenolinux_segment_fops = { - unsigned long value = 0; + open: xenolinux_segment_open, + release: xenolinux_segment_release, + ioctl: xenolinux_segment_ioctl, + check_media_change: xenolinux_segment_check, + revalidate: xenolinux_segment_revalidate, +}; - if (string == NULL) return 0; - while (!isdigit(*string) && *string != '\0') string++; +int __init xlseg_init(void) +{ + int i, result; + int counter; - while (isdigit(*string)) - { - value = value * 10 + (*string - '0'); - string++; - } + /* probe for disk information */ + memset (&xlseg_disk_info, 0, sizeof(xlseg_disk_info)); + xlseg_disk_info.count = 0; - return value; -} -static int proc_write_vhd(struct file *file, const char *buffer, - unsigned long count, void *data) -{ - char *local = kmalloc((count + 1) * sizeof(char), GFP_KERNEL); - char *string; - int loop; - int counter; - xv_disk_t xvd; - - memset (&xvd, 0, sizeof(xvd)); - - if (copy_from_user(local, buffer, count)) - { - return -EFAULT; - } - local[count] = '\0'; - - string = get_string(local); /* look for Domain */ - if (string == NULL) /* empty string */ - { - return count; - } - if (*string != 'd' && *string != 'D') - { - printk (KERN_ALERT - "error: domain specifier missing [%s]. should be \"domain\".\n", - string); - return count; - } - - string = get_string(NULL); /* domain number */ - if (string == NULL) - { - printk (KERN_ALERT "error: domain number missing\n"); - return count; - } - xvd.domain = (int) to_number(string); - - string = get_string(NULL); - if (string && (strcmp(string, "RO") == 0 || strcmp(string, "ro") == 0)) - { - xvd.mode = XEN_DISK_READ_ONLY; - } - else if (string && (strcmp(string, "RW") == 0 || strcmp(string, "rw") == 0)) - { - xvd.mode = XEN_DISK_READ_ONLY; - } - else - { - printk (KERN_ALERT - "error: bad mode [%s]. should be \"rw\" or \"ro\".\n", - string); - return count; - } - - string = get_string(NULL); /* look for Segment */ - if (string == NULL || (*string != 's' && *string != 'S')) - { - printk (KERN_ALERT - "error: segment specifier missing [%s]. should be \"segment\".\n", - string); - return count; - } - - string = get_string(NULL); /* segment number */ - if (string == NULL) - { - printk (KERN_ALERT "error: segment number missing\n"); - return count; - } - xvd.segment = (int) to_number(string); - - string = get_string(NULL); /* look for Extents */ - if (string == NULL || (*string != 'e' && *string != 'E')) - { - printk (KERN_ALERT - "error: extents specifier missing [%s]. should be \"extents\".\n", - string); - return count; - } - - string = get_string(NULL); /* number of extents */ - if (string == NULL) - { - printk (KERN_ALERT "error: number of extents missing\n"); - return count; - } - xvd.ext_count = (int) to_number(string); - - /* ignore parenthesis */ - - for (loop = 0; loop < xvd.ext_count; loop++) - { - string = get_string(NULL); /* look for Disk */ - if (string == NULL || (*string != 'd' && *string != 'D')) { - printk (KERN_ALERT - "hmm, extent disk specifier missing [%s]. should be \"disk\".\n", - string); - return count; + /* get lock xlblk_control_lock */ + counter = atomic_read(&xlblk_control_count); + atomic_inc(&xlblk_control_count); + /* release lock xlblk_control_lock */ } - string = get_string(NULL); /* disk number */ - if (string == NULL) - { - printk (KERN_ALERT "error: disk number missing\n"); - return count; + if ( hypervisor_request(NULL, XEN_BLOCK_PROBE_SEG, + (char *) &xlseg_disk_info, + 0, 0, (kdev_t) 0, + (struct gendisk *)NULL) ) + BUG(); + HYPERVISOR_block_io_op(); + while (atomic_read(&xlblk_control_count) != counter) barrier(); + + printk (KERN_ALERT "vhd block device probe:\n"); + for ( i = 0; i < xlseg_disk_info.count; i++ ) + { + printk (KERN_ALERT " %2d: type: %d, capacity: %ld\n", + i, xlseg_disk_info.disks[i].type, + xlseg_disk_info.disks[i].capacity); } - xvd.extents[loop].disk = (int) to_number(string); - string = get_string(NULL); /* look for Offset */ - if (string == NULL || (*string != 'o' && *string != 'O')) - { - printk (KERN_ALERT - "error: disk offset missing [%s]. should be \"offset\".\n", - string); - return count; + SET_MODULE_OWNER(&xenolinux_segment_fops); + result = register_blkdev(xlseg_major, "segment", &xenolinux_segment_fops); + if (result < 0) { + printk (KERN_ALERT "xenolinux segment: can't get major %d\n", + xlseg_major); + return result; } - string = get_string(NULL); /* offset */ - if (string == NULL) - { - printk (KERN_ALERT "error: offset missing\n"); - return count; - } - xvd.extents[loop].offset = to_number(string); - string = get_string(NULL); /* look for Size */ - if (string == NULL || (*string != 's' && *string != 'S')) - { - printk (KERN_ALERT - "error: extent size missing [%s]. should be \"size\".\n", - string); - return count; - } - string = get_string(NULL); /* size */ - if (string == NULL) + /* initialize global arrays in drivers/block/ll_rw_block.c */ + for (i = 0; i < XLSEG_MAX; i++) { - printk (KERN_ALERT "error: extent size missing\n"); - return count; + xlseg_blk_size[i] = xlseg_disk_info.disks[0].capacity ; + xlseg_blksize_size[i] = 512; + xlseg_hardsect_size[i] = 512; + xlseg_max_sectors[i] = 128; } - xvd.extents[loop].size = to_number(string); - } + xlseg_read_ahead = 8; - { - /* get lock xlblk_control_lock */ - counter = atomic_read(&xlblk_control_count); - atomic_inc(&xlblk_control_count); - /* release lock xlblk_control_lock */ - } + blk_size[xlseg_major] = xlseg_blk_size; + blksize_size[xlseg_major] = xlseg_blksize_size; + hardsect_size[xlseg_major] = xlseg_hardsect_size; + read_ahead[xlseg_major] = xlseg_read_ahead; + max_sectors[xlseg_major] = xlseg_max_sectors; - hypervisor_request (NULL, XEN_BLOCK_SEG_CREATE, (char *)&xvd, - 0, 0, (kdev_t) 0); - HYPERVISOR_block_io_op(); + blk_init_queue(BLK_DEFAULT_QUEUE(xlseg_major), do_xlseg_request); - while (atomic_read(&xlblk_control_count) != counter) barrier(); + /* + * Turn off barking 'headactive' mode. We dequeue buffer heads as + * soon as we pass them down to Xen. + */ + blk_queue_headactive(BLK_DEFAULT_QUEUE(xlseg_major), 0); - /* while ( blk_ring->resp_prod != 1 ) barrier(); */ + xlseg_register_disk(0, xlseg_disk_info.disks[0].capacity); - /* mdelay(1000); */ - - return count; + printk(KERN_ALERT + "XenoLinux Virtual Segment Device Driver installed [device: %d]\n", + xlseg_major); + return 0; } -/******************************************************************/ - -int __init xlseg_init(void) +void xlseg_register_disk(int idx, unsigned long capacity) { - vhd = create_proc_entry("xeno/dom0/vhd", 0644, NULL); - if (vhd == NULL) - { - panic ("xlseg_init: unable to create vhd proc entry\n"); - } - vhd->data = NULL; - vhd->read_proc = proc_read_vhd; - vhd->write_proc = proc_write_vhd; - vhd->owner = THIS_MODULE; - - memset(&xvd, 0, sizeof(xvd)); - - printk(KERN_ALERT "XenoLinux Virtual Disk Device Driver installed\n"); - return 0; + int units; + int minors; + struct gendisk *gd; + + /* plagarized from ide-probe.c::init_gendisk */ + + units = 2; /* from ide.h::MAX_DRIVES */ + +#define IDE_PARTN_BITS 6 /* from ide.h::PARTN_BITS */ + + minors = units * (1<sizes = kmalloc (minors * sizeof(int), GFP_KERNEL); + gd->part = kmalloc (minors * sizeof(struct hd_struct), GFP_KERNEL); + memset(gd->part, 0, minors * sizeof(struct hd_struct)); + + gd->major = xlseg_major; + gd->major_name = XLSEG_MAJOR_NAME; + gd->minor_shift = IDE_PARTN_BITS; + gd->max_p = 1<nr_real = units; + gd->real_devices = NULL; + gd->next = NULL; + gd->fops = &xenolinux_segment_fops; + gd->de_arr = kmalloc (sizeof *gd->de_arr * units, GFP_KERNEL); + gd->flags = kmalloc (sizeof *gd->flags * units, GFP_KERNEL); + + if (gd->de_arr) + memset (gd->de_arr, 0, sizeof *gd->de_arr * units); + + if (gd->flags) + memset (gd->flags, 0, sizeof *gd->flags * units); + + add_gendisk(gd); + + xlseg_disk_info.disks[idx].gendisk = gd; + + register_disk(gd, MKDEV(xlseg_major, 0), 1<part[loop].start_sect && gd->part[loop].nr_sects) + { + printk (KERN_ALERT + " %2d: 0x%6lx %8ld 0x%6lx %7ld\n", loop, + gd->part[loop].start_sect, gd->part[loop].start_sect, + gd->part[loop].nr_sects, gd->part[loop].nr_sects); + } + } + } + + return; } + static void __exit xlseg_cleanup(void) { - printk(KERN_ALERT "XenoLinux Virtual Disk Device Driver uninstalled\n"); + /* CHANGE FOR MULTIQUEUE */ + blk_cleanup_queue(BLK_DEFAULT_QUEUE(xlseg_major)); + + /* clean up global arrays */ + read_ahead[xlseg_major] = 0; + + if (blk_size[xlseg_major]) + kfree(blk_size[xlseg_major]); + blk_size[xlseg_major] = NULL; + + if (blksize_size[xlseg_major]) + kfree(blksize_size[xlseg_major]); + blksize_size[xlseg_major] = NULL; + + if (hardsect_size[xlseg_major]) + kfree(hardsect_size[xlseg_major]); + hardsect_size[xlseg_major] = NULL; + + /* XXX: free each gendisk */ + if (unregister_blkdev(xlseg_major, "block")) + printk(KERN_ALERT + "XenoLinux Virtual Segment Device Driver uninstalled w/ errs\n"); + else + printk(KERN_ALERT + "XenoLinux Virtual Segment Device Driver uninstalled\n"); + + return; } + #ifdef MODULE module_init(xlseg_init); module_exit(xlseg_cleanup); diff --git a/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_segment_proc.c b/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_segment_proc.c new file mode 100644 index 0000000000..8525d7855e --- /dev/null +++ b/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_segment_proc.c @@ -0,0 +1,280 @@ +/* + * xl_segment_proc.c + * + * XenoLinux virtual disk proc interface . + */ + + +#include +#include + +#include +#include +#include +#include + +#include +#include + +static struct proc_dir_entry *vhd; +xv_disk_t xvd; + +extern atomic_t xlblk_control_count; /* xl_block.c */ + +int hypervisor_request(void * id, + int operation, + char * buffer, + unsigned long block_number, + unsigned short block_size, + kdev_t device, + struct gendisk *gd); + +/******************************************************************/ + +static int proc_read_vhd(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + return 0; +} + +#define isdelim(c) \ + (c==' '||c==','||c=='\n'||c=='\r'||c=='\t'||c==':'||c=='('||c==')' ? 1 : 0) + +char *get_string(char *string) /* a bit like strtok */ +{ + static char *temp; + int loop = 0; + + if (string != NULL) + temp = string; + else + string = temp; + + try_again: + + while (!isdelim(string[loop])) + { + if (string[loop] == '\0') + return NULL; + loop++; + } + + string[loop] = '\0'; + temp = (string + loop + 1); + + if (loop == 0) + { + string = temp; + goto try_again; + } + + return string; +} + + +#define isdigit(c) (c >= '0' && c <= '9' ? 1 : 0) +unsigned long to_number(char *string) /* atoi */ +{ + unsigned long value = 0; + + if (string == NULL) return 0; + + while (!isdigit(*string) && *string != '\0') string++; + + while (isdigit(*string)) + { + value = value * 10 + (*string - '0'); + string++; + } + + return value; +} + +static int proc_write_vhd(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char *local = kmalloc((count + 1) * sizeof(char), GFP_KERNEL); + char *string; + int loop; + int counter; + xv_disk_t xvd; + + memset (&xvd, 0, sizeof(xvd)); + + if (copy_from_user(local, buffer, count)) + { + return -EFAULT; + } + local[count] = '\0'; + + string = get_string(local); /* look for Domain */ + if (string == NULL) /* empty string */ + { + return count; + } + if (*string != 'd' && *string != 'D') + { + printk (KERN_ALERT + "error: domain specifier missing [%s]. should be \"domain\".\n", + string); + return count; + } + + string = get_string(NULL); /* domain number */ + if (string == NULL) + { + printk (KERN_ALERT "error: domain number missing\n"); + return count; + } + xvd.domain = (int) to_number(string); + + string = get_string(NULL); + if (string && (strcmp(string, "RO") == 0 || strcmp(string, "ro") == 0)) + { + xvd.mode = XEN_DISK_READ_ONLY; + } + else if (string && (strcmp(string, "RW") == 0 || strcmp(string, "rw") == 0)) + { + xvd.mode = XEN_DISK_READ_WRITE; + } + else + { + printk (KERN_ALERT + "error: bad mode [%s]. should be \"rw\" or \"ro\".\n", + string); + return count; + } + + string = get_string(NULL); /* look for Segment */ + if (string == NULL || (*string != 's' && *string != 'S')) + { + printk (KERN_ALERT + "error: segment specifier missing [%s]. should be \"segment\".\n", + string); + return count; + } + + string = get_string(NULL); /* segment number */ + if (string == NULL) + { + printk (KERN_ALERT "error: segment number missing\n"); + return count; + } + xvd.segment = (int) to_number(string); + + string = get_string(NULL); /* look for Extents */ + if (string == NULL || (*string != 'e' && *string != 'E')) + { + printk (KERN_ALERT + "error: extents specifier missing [%s]. should be \"extents\".\n", + string); + return count; + } + + string = get_string(NULL); /* number of extents */ + if (string == NULL) + { + printk (KERN_ALERT "error: number of extents missing\n"); + return count; + } + xvd.ext_count = (int) to_number(string); + + /* ignore parenthesis */ + + for (loop = 0; loop < xvd.ext_count; loop++) + { + string = get_string(NULL); /* look for Disk */ + if (string == NULL || (*string != 'd' && *string != 'D')) + { + printk (KERN_ALERT + "hmm, extent disk specifier missing [%s]. should be \"disk\".\n", + string); + return count; + } + string = get_string(NULL); /* disk number */ + if (string == NULL) + { + printk (KERN_ALERT "error: disk number missing\n"); + return count; + } + xvd.extents[loop].disk = (int) to_number(string); + + string = get_string(NULL); /* look for Offset */ + if (string == NULL || (*string != 'o' && *string != 'O')) + { + printk (KERN_ALERT + "error: disk offset missing [%s]. should be \"offset\".\n", + string); + return count; + } + string = get_string(NULL); /* offset */ + if (string == NULL) + { + printk (KERN_ALERT "error: offset missing\n"); + return count; + } + xvd.extents[loop].offset = to_number(string); + + string = get_string(NULL); /* look for Size */ + if (string == NULL || (*string != 's' && *string != 'S')) + { + printk (KERN_ALERT + "error: extent size missing [%s]. should be \"size\".\n", + string); + return count; + } + string = get_string(NULL); /* size */ + if (string == NULL) + { + printk (KERN_ALERT "error: extent size missing\n"); + return count; + } + xvd.extents[loop].size = to_number(string); + } + + { + /* get lock xlblk_control_lock */ + counter = atomic_read(&xlblk_control_count); + atomic_inc(&xlblk_control_count); + /* release lock xlblk_control_lock */ + } + if (hypervisor_request (NULL, XEN_BLOCK_SEG_CREATE, (char *)&xvd, + 0, 0, (kdev_t) 0, + (struct gendisk *)NULL)) + BUG(); + HYPERVISOR_block_io_op(); + + while (atomic_read(&xlblk_control_count) != counter) barrier(); + + return count; +} + +/******************************************************************/ + +int __init xlseg_proc_init(void) +{ + vhd = create_proc_entry("xeno/dom0/vhd", 0644, NULL); + if (vhd == NULL) + { + panic ("xlseg_init: unable to create vhd proc entry\n"); + } + vhd->data = NULL; + vhd->read_proc = proc_read_vhd; + vhd->write_proc = proc_write_vhd; + vhd->owner = THIS_MODULE; + + memset(&xvd, 0, sizeof(xvd)); + + printk(KERN_ALERT "XenoLinux Virtual Disk Device Monitor installed\n"); + return 0; +} + +static void __exit xlseg_proc_cleanup(void) +{ + printk(KERN_ALERT "XenoLinux Virtual Disk Device Monitor uninstalled\n"); +} + +#ifdef MODULE +module_init(xlseg_proc_init); +module_exit(xlseg_proc_cleanup); +#endif diff --git a/xenolinux-2.4.21-pre4-sparse/drivers/block/ll_rw_blk.c b/xenolinux-2.4.21-pre4-sparse/drivers/block/ll_rw_blk.c index 470b206726..842dd069f1 100644 --- a/xenolinux-2.4.21-pre4-sparse/drivers/block/ll_rw_blk.c +++ b/xenolinux-2.4.21-pre4-sparse/drivers/block/ll_rw_blk.c @@ -1505,6 +1505,7 @@ int __init blk_dev_init(void) #ifdef CONFIG_XENOLINUX_BLOCK xlblk_init(); xlseg_init(); + xlseg_proc_init(); #endif return 0; diff --git a/xenolinux-2.4.21-pre4-sparse/include/linux/blk.h b/xenolinux-2.4.21-pre4-sparse/include/linux/blk.h index 0be65ab99d..e7fa201955 100644 --- a/xenolinux-2.4.21-pre4-sparse/include/linux/blk.h +++ b/xenolinux-2.4.21-pre4-sparse/include/linux/blk.h @@ -328,6 +328,13 @@ static void floppy_off(unsigned int nr); /* #define DEVICE_INTR */ #define DEVICE_NR(device) (MINOR(device)) +#elif (MAJOR_NR == XLSEG_MAJOR) + +#define DEVICE_NAME "xeno segment" +#define DEVICE_REQUEST do_xlseg_request +/* #define DEVICE_INTR */ +#define DEVICE_NR(device) (MINOR(device)) + #endif /* MAJOR_NR == whatever */ /* provide DEVICE_xxx defaults, if not explicitly defined diff --git a/xenolinux-2.4.21-pre4-sparse/include/linux/major.h b/xenolinux-2.4.21-pre4-sparse/include/linux/major.h index dfcb6f79f0..9cac1c2881 100644 --- a/xenolinux-2.4.21-pre4-sparse/include/linux/major.h +++ b/xenolinux-2.4.21-pre4-sparse/include/linux/major.h @@ -145,7 +145,8 @@ #define UMEM_MAJOR 116 /* http://www.umem.com/ Battery Backed RAM */ -#define XLBLK_MAJOR 123 /* XenoLinux Block Device */ +/* note: 123, 124, 125, 126 and 234, 235, 236, 237 are defined in xeno_major */ +#include #define RTF_MAJOR 150 #define RAW_MAJOR 162 diff --git a/xenolinux-2.4.21-pre4-sparse/init/do_mounts.c b/xenolinux-2.4.21-pre4-sparse/init/do_mounts.c index b0b143a264..ddf2f96a39 100644 --- a/xenolinux-2.4.21-pre4-sparse/init/do_mounts.c +++ b/xenolinux-2.4.21-pre4-sparse/init/do_mounts.c @@ -235,6 +235,10 @@ static struct dev_name_struct { { "xhdb", 0x7C00 }, { "xhdc", 0x7D00 }, { "xhdd", 0x7E00 }, + { "vhda", 0xEA00 }, + { "vhdb", 0xEB00 }, + { "vhdc", 0xEC00 }, + { "vhdd", 0xED00 }, #endif { "nftla", 0x5d00 }, { "nftlb", 0x5d10 }, -- 2.30.2